/*
IfExplorer, an open source file manager for the Android system.
Copyright (C) 2014 Kevin Lin
<chenbin.lin@tpv-tech.com>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gem.kevin.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import com.sparseboolean.ifexplorer.IfConfig;
import com.sparseboolean.ifexplorer.IfStorageVolume;
import com.sparseboolean.ifexplorer.R;
import android.content.Context;
import android.content.res.Resources;
import android.os.Environment;
import android.os.StatFs;
import android.os.storage.StorageManager;
import android.util.Log;
/** @author kevin.lin */
public final class StorageUtil {
public class StorageVolumeStatFs {
private long mTotalSize = 0;
private long mAvailableSize = 0;
private long mUsedSize = 0;
StorageVolumeStatFs(IfStorageVolume storageVolume) {
if (storageVolume != null) {
final StatFs stat = new StatFs(storageVolume.getPath());
final long blockSize = stat.getBlockSize();
final long totalBlocks = stat.getBlockCount();
final long availableBlocks = stat.getAvailableBlocks();
mTotalSize = totalBlocks * blockSize;
mAvailableSize = availableBlocks * blockSize;
mUsedSize = mTotalSize - mAvailableSize;
}
}
public long getAvailableSize() {
return mAvailableSize;
}
public long getTotalSize() {
return mTotalSize;
}
public long getUsedSize() {
return mUsedSize;
}
}
private static final String TAG = "IfManager-Utils";
private static final boolean KLOG = false;
private static final boolean tempLOG = true;
/* favorites */
public static final String PATH_HOME = Environment
.getExternalStorageDirectory().getPath();
public static final String PATH_DOWNLOADS = PATH_HOME + "/"
+ Environment.DIRECTORY_DOWNLOADS;
public static final String PATH_MUSIC = PATH_HOME + "/"
+ Environment.DIRECTORY_MUSIC;
public static final String PATH_PICTURES = PATH_HOME + "/"
+ Environment.DIRECTORY_PICTURES;
public static final String PATH_MOVIES = PATH_HOME + "/"
+ Environment.DIRECTORY_MOVIES;
public static final String PATH_DCIM = PATH_HOME + "/"
+ Environment.DIRECTORY_DCIM;
public static float GigaByteToByte = 1024 * 1024 * 1024;
/* exclude some android directories for searching */
private static ArrayList<String> sExcludeSearchPaths = null;
public static final int TYPE_AUDIO = 1;
public static final int TYPE_VIDEO = 2;
public static final int TYPE_IMAGE = 3;
public static final int TYPE_FILE = 4;
public static final int TYPE_SDCARD = 5;
public static final int TYPE_UDISK = 6;
public static final int TYPE_APKFILE = 7;
public static final int TYPE_HOME = 8;
public static final int TYPE_ROOT = 9;
/* Android Linux system directories and files */
private static ArrayList<String> sAndroidSysPaths = null;
// Storage position
public static final int USBPort0 = 0;
public static final int USBPort1 = 1;
public static final int USBPort2 = 2;
public static final int USBPort3 = 3;
public static final int USBPort4 = 4;
public static final int USBPort5 = 5;
public static final int SDSlot = 6;
public static final int Internal = 7;
// For covering any other non configurable external storage policy
// A Linux device name style
public static final int USBSDA = 8;
public static final int USBSDB = 9;
public static final int USBSDC = 10;
public static final int USBSDD = 11;
public static final int USBSDE = 12;
public static final int USBSDF = 13;
// 'diskid' file related
public static final String DISKID_FILE_NAME = ".diskid";
public static final String DISKID_TAG_DISKNAME = "DISKNAME";
public static final String DISKID_TAG_DISKVENDOR = "DISKVENDOR";
public static final String DISKID_TAG_DISKMODEL = "DISKMODEL";
// 'volid' file related
public static final String VOLID_FILE_NAME = ".volid";
public static final String VOLID_TAG_LABEL = "LABEL";
public static final String VOLID_TAG_TYPE = "TYPE";
public static final String VOLID_TAG_ENCODING = "ENCODING";
public static final String BRACKET = "\"";
public static boolean detectMountStateFromProc(String path) {
if (tempLOG) {
Log.i("@temp", "detectMountStateFromProc --- for path: " + path);
}
File procFile = new File(IfConfig.MOUNT_PROC_PATH);
if (procFile.exists() && procFile.isFile()) {
try {
BufferedReader input = new BufferedReader(new FileReader(
procFile));
String line;
while ((line = input.readLine()) != null) {
if (line.contains(path)) {
input.close();
return true;
}
}
input.close();
} catch (IOException ioException) {
Log.i(TAG, "io error when try to read /proc/mounts.");
}
}
if (tempLOG) {
Log.i("@temp", "not mounted path: " + path);
}
return false;
}
public static ArrayList<String> getExcludeSearchPath() {
if (sExcludeSearchPaths != null) {
return sExcludeSearchPaths;
} else {
sExcludeSearchPaths = new ArrayList<String>();
sExcludeSearchPaths.add("/mnt/obb");
sExcludeSearchPaths.add("/mnt/asec");
sExcludeSearchPaths.add("/mnt/secure");
}
return sExcludeSearchPaths;
}
public static String getExtraMountRoot() {
// return "/mnt";
return "/mnt";
}
public static String getHomeDir() {
if (IfConfig.PRODUCT_ROCK_CHIP) {
return "/sdcard";
}
if (android.os.Build.VERSION.SDK_INT >= 17) {
int id = 0;
try {
Class<?> class_UserHandle = null;
try {
class_UserHandle = Class.forName("android.os.UserHandle");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (class_UserHandle != null) {
Method method_myUserId = class_UserHandle.getMethod(
"myUserId", new Class[] {});
try {
id = (Integer) method_myUserId.invoke(class_UserHandle,
new Object[] {});
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return "/storage/emulated/" + id;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return "/sdcard";
}
} else {
return "/sdcard";
}
}
public static boolean isAndroidSysFile(String path) {
if (path == null) {
return false;
}
if (sAndroidSysPaths == null) {
sAndroidSysPaths = new ArrayList<String>();
// DIRS
sAndroidSysPaths.add("/acct/");
sAndroidSysPaths.add("/cache/");
sAndroidSysPaths.add("/config/");
sAndroidSysPaths.add("/d/");
sAndroidSysPaths.add("/data/");
sAndroidSysPaths.add("/dev/");
sAndroidSysPaths.add("/proc/");
sAndroidSysPaths.add("/root/");
sAndroidSysPaths.add("/sbin/");
sAndroidSysPaths.add("/sys/");
sAndroidSysPaths.add("/system");
sAndroidSysPaths.add("/usbdrive/");
sAndroidSysPaths.add("/vendor/");
// FILES
sAndroidSysPaths.add("/init");
sAndroidSysPaths.add("/default.prop");
}
if (sAndroidSysPaths.contains(path)) {
return true;
} else {
for (String sysPath : sAndroidSysPaths) {
if (path.startsWith(sysPath)
|| (path + "/").startsWith(sysPath)) {
return true;
}
}
return false;
}
}
public static boolean isExcludeSearchPath(String absolutePath,
ArrayList<String> reservedDirs) {
// kevin@xmic: special handle for trashed in Windows, Linux and MacOSX,
// on SD APK host,
// LOST.DIR, etc
if (absolutePath.contains("$RECYCLE.BIN")
|| absolutePath.contains(".android_secure")
|| absolutePath.contains("Recycled")
|| absolutePath.contains("RECYCLER")
|| absolutePath.contains("System Volume Information")
|| absolutePath.contains(".Trashes")
|| absolutePath.contains(".DS_Store")
|| absolutePath.contains(".Spotlight-V")
|| absolutePath.contains("LOST.DIR")
|| absolutePath.contains(".Spotlight-V")
|| absolutePath.contains("Androind/obb")
|| absolutePath.contains("emulated/legacy")
|| absolutePath.contains("lost+found")) {
return true;
}
// if reserved directory is explicitly specified, make sure we don't
// exclude directory listed in it
if (reservedDirs != null) {
for (String reserved : reservedDirs) {
if (absolutePath.startsWith(reserved)) {
return false;
}
}
}
return false;
}
public static boolean isExtendPartition(String mountPoint) {
if (mountPoint == null) {
return false;
}
final StatFs stat;
try {
stat = new StatFs(mountPoint);
} catch (IllegalArgumentException e) {
Log.e(TAG, "illegal argument: " + mountPoint
+ " for StatFs intialization");
return false;
}
final long totalBlocks = stat.getBlockCount();
final long blockSize = stat.getBlockSize();
final long totalSize = totalBlocks * blockSize;
final double totalSizeInGB = totalSize / GigaByteToByte;
// Log.i(TAG, "total size %.2fGB: " + totalSizeInGB + " for path" +
// mountPoint);
// kevin@xmic: small than 20MB, assume as an extended partition
if (totalSizeInGB < 0.02f && totalSizeInGB > 0) {
return true;
}
return false;
}
// kevin@xmic: tricky for skipping unnecessary validation on first volume of
// disk
public static boolean isFirstVolume(String mountPoint) {
if (mountPoint.contains("p1")) {
return true;
} else {
return false;
}
}
// kevin@xmic: hard-coded primary volume
// primary mount point(EXTERNAL_STORAGE) is configured in init.[product].rc
public static boolean isPrimaryVolume(String mountPoint) {
if (mountPoint == null) {
return false;
}
if (Environment.getExternalStorageDirectory().getPath()
.equals(mountPoint)) {
return true;
} else {
return false;
}
}
/*
* kevin@xmic: A method to check if a volume is a logical partition Well,
* doing the stuff by counting volume size in Java space could be
* inefficient choice underlying facilities is responsible to get logical
* partition filtered as mount candidate
*/
public static boolean isValidVolume(String mountPoint) {
if (mountPoint == null) {
return false;
}
final StatFs stat;
try {
stat = new StatFs(mountPoint);
} catch (IllegalArgumentException e) {
Log.e(TAG, "illegal argument: " + mountPoint
+ " for StatFs intialization");
return false;
}
final long totalBlocks = stat.getBlockCount();
final long blockSize = stat.getBlockSize();
final long totalSize = totalBlocks * blockSize;
final double totalSizeInGB = totalSize / GigaByteToByte;
// Log.i(TAG, "total size %.2fGB: " + totalSizeInGB + " for path" +
// mountPoint);
// kevin@xmic: small than 20MB, considered as non valid volume (might be
// an extended volume
if (totalSizeInGB < 0.02f) {
return false;
}
return true;
}
// Instance fields
private final Context mContext;
/* mount points */
// mount points should be unique, so we use HashSet
private static final HashSet<String> sMountPoints = new HashSet<String>();
/* storage volumes and storage unique id to volume map */
private static final ArrayList<IfStorageVolume> sStorageVolumes = new ArrayList<IfStorageVolume>();
private static final HashMap<String, IfStorageVolume> sMountPointVolumeMap = new HashMap<String, IfStorageVolume>();
private static final HashMap<String, IfStorageVolume> sDeviceNodeVolumeMap = new HashMap<String, IfStorageVolume>();
// HashMap to keep disk names and volume labels for mount points
private static final HashMap<String, String> sDiskIds = new HashMap<String, String>();
private static final HashMap<String, String> sVolumeIds = new HashMap<String, String>();
// HashMap to keep a top level table for interested IDs and its hash map
public static final HashMap<String, HashMap<String, String>> sStorageIdMap = new HashMap<String, HashMap<String, String>>();
private static StorageUtil sStorageUtil = null;
public static int getMountPort(String path) {
if (path == null) {
return -1;
}
if (path.contains("emulated") || path.contains("internal")) {
return Internal;
} else if (path.contains("sdcard") || path.contains("external_sd")) {
return SDSlot;
} else if (path.contains("usb0") || path.contains("USB_DISK0")) {
return USBPort0;
} else if (path.contains("usb1") || path.contains("USB_DISK1")) {
return USBPort1;
} else if (path.contains("usb2") || path.contains("USB_DISK2")) {
return USBPort2;
} else if (path.contains("usb3") || path.contains("USB_DISK3")) {
return USBPort3;
} else if (path.contains("usb4") || path.contains("USB_DISK4")) {
return USBPort4;
} else if (path.contains("sda")) {
return USBSDA;
} else if (path.contains("sdb")) {
return USBSDB;
} else if (path.contains("sdc") && !path.contains("sdcard")) {
return USBSDC;
} else if (path.contains("sdd")) {
return USBSDD;
} else if (path.contains("sde")) {
return USBSDE;
} else if (path.contains("sdf")) {
return USBSDF;
}
return -1;
}
public static StorageUtil getSingleton(Context context) {
if (sStorageUtil == null && context != null) {
sStorageUtil = new StorageUtil(context);
}
return sStorageUtil;
}
private StorageUtil(Context context) {
mContext = context;
initializeIfStorageVolumes();
initializeStorageIds();
}
public void createIfStorageVolumeByPath(String path) {
Log.i(TAG, "createIfStorageVolumeByPath, path=" + path);
boolean removable = true;
int descriptionId = getStorageDescriptionResId(path);
boolean primary = false;
boolean emulated = path.contains("emulated");
IfStorageVolume volume = new IfStorageVolume(null, path, descriptionId,
primary, removable, emulated, null);
sMountPointVolumeMap.put(path, volume);
if (!sStorageVolumes.contains(volume)) {
sStorageVolumes.add(volume);
}
sMountPoints.add(path);
fulfillIfStorageVolumesByProc();
}
public String getCachedId(String path, String idTag) {
HashMap<String, String> map = sStorageIdMap.get(idTag);
if (map == null) {
if (KLOG) {
Log.i(TAG, "== kevin@xmic == Can't get hash map for " + idTag);
}
return null;
}
return map.get(path);
}
public IfStorageVolume getIfStorageVolumeFromPath(String path) {
if (sMountPointVolumeMap == null) {
return null;
}
return sMountPointVolumeMap.get(path);
}
public ArrayList<IfStorageVolume> getIfStorageVolumes() {
return sStorageVolumes;
}
public ArrayList<String> getMountedStorageVolumePaths() {
ArrayList<String> result = new ArrayList<String>();
if (sStorageVolumes == null) {
return null;
}
for (IfStorageVolume volume : sStorageVolumes) {
String path = volume.getPath();
if (isMounted(path)) {
result.add(path);
}
}
return result;
}
public String getMountpoint(String containingPath) {
for (String mountPoint : sMountPoints) {
if (containingPath.contains(mountPoint)) {
return mountPoint;
}
}
return null;
}
public ArrayList<String> getMountpointsForMountedBuddy(String buddy) {
if (buddy == null) {
return null;
}
int port = getMountPort(buddy);
ArrayList<String> matchs = new ArrayList<String>();
HashSet<String> all = sMountPoints;
for (String item : all) {
if (getMountPort(item) == port && !item.equals(buddy)
&& detectMountStateFromProc(item)) {
matchs.add(item);
}
}
return matchs;
}
public String getStorageDescription(int resId) {
Resources res = mContext.getResources();
return res != null ? res.getString(resId) : null;
}
public int getStorageDescriptionResId(String path) {
if (path == null) {
return -1;
}
if (path.contains("sdcard") || path.contains("emulated")) {
if (IfConfig.PRODUCT_BUILT_IN_SDCARD) {
return R.string.internal_sdcard;
} else {
return R.string.sdcard_storage;
}
} else if (path.contains("internal_sd")) {
return R.string.home_dir;
} else if (path.contains("extsd") || path.contains("external_sd")) {
return R.string.sdcard_storage;
} else if (path.contains("usb0") || path.contains("USB_DISK0")) {
return R.string.usb_storage;
} else if (path.contains("usb1") || path.contains("USB_DISK1")) {
return R.string.usb1_storage;
} else if (path.contains("usb2") || path.contains("USB_DISK2")) {
return R.string.usb2_storage;
} else if (path.contains("usb3") || path.contains("USB_DISK3")) {
return R.string.usb3_storage;
} else if (path.contains("usb4") || path.contains("USB_DISK4")) {
return R.string.usb4_storage;
} else if (path.contains("usb")) {
return R.string.usb_storage;
} else if (path.contains("sda")) {
return R.string.usb_storage_a;
} else if (path.contains("sdb")) {
return R.string.usb_storage_b;
} else if (path.contains("sdc") && !path.contains("sdcard")) {
return R.string.usb_storage_c;
} else if (path.contains("sdd")) {
return R.string.usb_storage_d;
} else if (path.contains("sde")) {
return R.string.usb_storage_e;
} else if (path.contains("sdf")) {
return R.string.usb_storage_f;
}
return -1;
}
public String getStringFromResId(int resid) {
return mContext.getResources().getString(resid);
}
public ArrayList<String> getSynthesizedStorageVolumePaths(
ArrayList<String> toSynthesize) {
if (toSynthesize == null) {
return null;
}
ArrayList<String> result = new ArrayList<String>();
for (String item : toSynthesize) {
// Add all to-synthesize by default,
// We might want to filter some volumes in the future
result.add(item);
}
return result;
}
// kevin@xmic: Be sure to get this method called before using getCachedId
// method
public void initializeStorageIds() {
// Currently we are interested in disk name(vendor+model) and volume
// label
sStorageIdMap.put(DISKID_TAG_DISKNAME, sDiskIds);
sStorageIdMap.put(DISKID_TAG_DISKVENDOR, sDiskIds);
sStorageIdMap.put(DISKID_TAG_DISKMODEL, sDiskIds);
sStorageIdMap.put(VOLID_TAG_LABEL, sVolumeIds);
}
public boolean isMounted(IfStorageVolume storageVolume) {
if (storageVolume == null) {
return false;
}
String path = storageVolume.getPath();
if (detectMountStateFromProc(path)) {
return true;
} else {
return false;
}
}
public boolean isMounted(String mountPoint) {
if (detectMountStateFromProc(mountPoint)) {
return true;
} else {
return false;
}
}
public boolean isMountPoint(String path) {
if (sMountPoints != null) {
return sMountPoints.contains(path);
}
return false;
}
public boolean isPathDirtyForUsage(String path, int usage) {
// TODO: to implement
return true;
}
public String readDiskIdForPath(String path, String diskidTag) {
String diskidFilePath = path + "/" + DISKID_FILE_NAME;
File diskidFile = new File(diskidFilePath);
FileInputStream fistream;
try {
fistream = new FileInputStream(diskidFile);
} catch (FileNotFoundException e) {
Log.e(TAG, "Can't find diskid file from " + diskidFilePath);
return cacheId(path, diskidTag, null);
}
InputStreamReader isreader = null;
BufferedReader bufreader = null;
String result = null;
String diskid = null;
// All known disk IDs are named in Latin language, UTF-8 would always be
// enough
try {
isreader = new InputStreamReader(fistream, "UTF-8");
bufreader = new BufferedReader(isreader);
while ((diskid = bufreader.readLine()) != null) {
if (diskid.contains(diskidTag)) {
if (KLOG) {
Log.i(TAG, "Get disk id: " + diskid + "for " + path);
}
int openBracket = diskid.indexOf(BRACKET);
int closeBracket = diskid.lastIndexOf(BRACKET);
if (closeBracket > (openBracket + 1)) {
result = diskid
.substring(openBracket + 1, closeBracket)
.trim();
Log.i(TAG, "Disk Name is: " + result);
} else {
result = null;
}
}
}
bufreader.close();
isreader.close();
fistream.close();
return cacheId(path, diskidTag, result);
} catch (IOException e) {
Log.e(TAG, "Failed due exception while read {" + diskidTag
+ "} from " + diskidFilePath);
}
return cacheId(path, diskidTag, result);
}
public String readDiskNameForPath(String path) {
String diskidFilePath = path + "/" + DISKID_FILE_NAME;
File diskidFile = new File(diskidFilePath);
String diskVendor = null;
String diskModel = null;
String diskName = null;
FileInputStream fistream;
try {
fistream = new FileInputStream(diskidFile);
} catch (FileNotFoundException e) {
Log.w(TAG, "Can't find diskid file from " + diskidFilePath);
return cacheId(path, DISKID_TAG_DISKNAME, null);
}
InputStreamReader isreader = null;
BufferedReader bufreader = null;
String diskid = null;
// All known disk IDs are named in Latin language, UTF-8 would always be
// enough
try {
isreader = new InputStreamReader(fistream, "UTF-8");
bufreader = new BufferedReader(isreader);
while ((diskid = bufreader.readLine()) != null) {
if (diskid.contains(DISKID_TAG_DISKVENDOR)) {
int openBracket = diskid.indexOf(BRACKET);
int closeBracket = diskid.lastIndexOf(BRACKET);
if (closeBracket > (openBracket + 1)) {
diskVendor = diskid.substring(openBracket + 1,
closeBracket).trim();
Log.i(TAG, "Disk vendor is: " + diskVendor);
} else {
diskVendor = null;
}
} else if (diskid.contains(DISKID_TAG_DISKMODEL)) {
int openBracket = diskid.indexOf(BRACKET);
int closeBracket = diskid.lastIndexOf(BRACKET);
if (closeBracket > (openBracket + 1)) {
diskModel = diskid.substring(openBracket + 1,
closeBracket).trim();
Log.i(TAG, "Disk model is: " + diskModel);
} else {
diskModel = null;
}
}
}
bufreader.close();
isreader.close();
fistream.close();
// Combine vendor and model as disk name
if (diskVendor != null && diskModel != null) {
diskName = diskVendor + " " + diskModel;
} else if (diskModel == null) {
diskName = diskVendor;
}
return cacheId(path, DISKID_TAG_DISKNAME, diskName);
} catch (IOException e) {
Log.e(TAG, "Failed due exception while read disk name from "
+ diskidFilePath);
}
return cacheId(path, DISKID_TAG_DISKNAME, diskName);
}
public String readVolIdForPath(String path, String volidTag) {
String volidFilePath = path + "/" + VOLID_FILE_NAME;
File volidFile = new File(volidFilePath);
FileInputStream fistream;
try {
fistream = new FileInputStream(volidFile);
} catch (FileNotFoundException e) {
Log.w(TAG, "Can't find volid file from " + volidFilePath);
return cacheId(path, volidTag, null);
}
InputStreamReader isreader = null;
BufferedReader bufreader = null;
String result = null;
String volid = null;
boolean isUtf8 = true;
try {
// firstly try to read 'volid' file in UTF-8 encoding
isreader = new InputStreamReader(fistream, "UTF-8");
bufreader = new BufferedReader(isreader);
while ((volid = bufreader.readLine()) != null) {
if (volid.contains(volidTag)) {
if (KLOG) {
Log.i(TAG, "Get volume id: " + volid + "for " + path);
}
int openBracket = volid.indexOf(BRACKET);
int closeBracket = volid.lastIndexOf(BRACKET);
if (closeBracket > (openBracket + 1)) {
result = volid.substring(openBracket + 1, closeBracket)
.trim();
} else {
result = null;
}
}
if (volid.contains("ENCODING=\"ansi\"")) {
// stop read as UTF-8 and reset reader
bufreader.close();
bufreader = null;
isreader.close();
isreader = null;
fistream.close();
fistream = null;
isUtf8 = false;
break;
}
}
if (!isUtf8) {
try {
fistream = new FileInputStream(volidFile);
} catch (FileNotFoundException e) {
Log.w(TAG, "Can't find volid file from " + volidFilePath);
return cacheId(path, volidTag, null);
}
isreader = new InputStreamReader(fistream, "GBK");
bufreader = new BufferedReader(isreader);
while ((volid = bufreader.readLine()) != null) {
if (volid.contains(volidTag)) {
int openBracket = volid.indexOf(BRACKET);
int closeBracket = volid.lastIndexOf(BRACKET);
if (closeBracket > (openBracket + 1)) {
result = volid.substring(openBracket + 1,
closeBracket).trim();
} else {
result = null;
}
}
}
}
bufreader.close();
isreader.close();
fistream.close();
return cacheId(path, volidTag, result);
} catch (IOException e) {
Log.e(TAG, "Failed due exception while read {" + volidTag
+ "} from " + volidFilePath);
}
return cacheId(path, volidTag, result);
}
public StorageVolumeStatFs statFsContainerFileSystem(String filePath) {
if (sMountPoints == null || filePath == null) {
return null;
} else {
String fileCanonicalPath;
try {
fileCanonicalPath = new File(filePath).getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
return null;
}
for (String mountPoint : sMountPoints) {
if (fileCanonicalPath.equals(mountPoint)
|| fileCanonicalPath.startsWith(mountPoint)) {
return new StorageVolumeStatFs(
getIfStorageVolumeFromPath(mountPoint));
}
}
return null;
}
}
private void clearIfStorageVolumeInfo() {
if (!sMountPointVolumeMap.isEmpty()) {
sMountPointVolumeMap.clear();
}
if (!sDeviceNodeVolumeMap.isEmpty()) {
sDeviceNodeVolumeMap.clear();
}
if (!sStorageVolumes.isEmpty()) {
sStorageVolumes.clear();
}
if (!sMountPoints.isEmpty()) {
sMountPoints.clear();
}
}
private void createIfStorageVolumesByProc() {
File procFile = new File(IfConfig.MOUNT_PROC_PATH);
if (procFile.exists() && procFile.isFile()) {
try {
BufferedReader input = new BufferedReader(new FileReader(
procFile));
String line;
while ((line = input.readLine()) != null) {
String[] fields = line.split(" ");
String devNode = fields[0];
if (devNode.contains("block")
&& !devNode.contains("mtdblock")) {
String path = fields[1];
String fsFormat = fields[2];
if (!sDeviceNodeVolumeMap.containsKey(devNode)
&& !path.equals(IfConfig.ANDROID_ASEC_PATH)) {
// FIXME
boolean isSDStorage = (devNode.contains("mmcblk") || path
.contains("sdcard"));
boolean removable = !(isSDStorage && IfConfig.PRODUCT_BUILT_IN_SDCARD);
int descriptionId = getStorageDescriptionResId(path);
boolean primary = isSDStorage;
boolean emulated = path.contains("emulated");
IfStorageVolume volume = new IfStorageVolume(
devNode, path, descriptionId, primary,
removable, emulated, fsFormat);
sDeviceNodeVolumeMap.put(devNode, volume);
sMountPointVolumeMap.put(path, volume);
if (!sStorageVolumes.contains(volume)) {
sStorageVolumes.add(volume);
}
sMountPoints.add(path);
}
} else {
continue;
}
}
input.close();
} catch (IOException ioException) {
Log.i(TAG, "io error when try to read /proc/mounts.");
}
}
}
private void fulfillIfStorageVolumesByProc() {
if (KLOG) {
Log.i(TAG, "Fulfill IfStorageVolumes by proc.");
}
File procFile = new File(IfConfig.MOUNT_PROC_PATH);
if (procFile.exists() && procFile.isFile()) {
try {
BufferedReader input = new BufferedReader(new FileReader(
procFile));
String line;
while ((line = input.readLine()) != null) {
String[] fields = line.split(" ");
String devNode = fields[0];
String path = fields[1];
if (devNode.contains("block")
&& !devNode.contains("mtdblock")
&& sMountPointVolumeMap.containsKey(path)) {
String fsFormat = fields[2];
// FIXME
boolean isSDStorage = (devNode.contains("mmcblk") || path
.contains("sdcard"));
boolean removable = !(isSDStorage && IfConfig.PRODUCT_BUILT_IN_SDCARD);
int descriptionId = getStorageDescriptionResId(path);
boolean primary = isSDStorage;
IfStorageVolume if_volume = sMountPointVolumeMap
.get(path);
if (if_volume != null) {
if_volume.setDevNode(devNode);
sDeviceNodeVolumeMap.put(devNode, if_volume);
if_volume.setDescriptionId(descriptionId);
if_volume.setFilesystemFormat(fsFormat);
if_volume.setRemovable(removable);
if_volume.setPrimary(primary);
}
} else {
continue;
}
}
input.close();
} catch (IOException ioException) {
Log.i(TAG, "io error when try to read /proc/mounts.");
}
}
}
private void initializeIfStorageVolumes() {
clearIfStorageVolumeInfo();
ArrayList<Object> storageVolumeList = new ArrayList<Object>();
Method method_getVolumeList = null;
try {
method_getVolumeList = StorageManager.class.getMethod(
"getVolumeList", new Class[] {});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if (method_getVolumeList != null) {
StorageManager storageManager = (StorageManager) mContext
.getSystemService(Context.STORAGE_SERVICE);
Object storageVolumesArray = null;
try {
storageVolumesArray = method_getVolumeList.invoke(
storageManager, new Object[] {});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (storageVolumesArray != null) {
int length = java.lang.reflect.Array
.getLength(storageVolumesArray);
for (int i = 0; i < length; i++) {
storageVolumeList.add(java.lang.reflect.Array.get(
storageVolumesArray, i));
}
}
}
initializeIfStorageVolumesInner(storageVolumeList);
// For Rock chip solution
initializeIfStorageVolumesInnerForRKPlatform();
}
private void initializeIfStorageVolumesInnerForRKPlatform() {
String internal_path = "/mnt/internal_sd";
IfStorageVolume volume = new IfStorageVolume(internal_path, false,
false, false);
sMountPointVolumeMap.put(internal_path, volume);
if (!sStorageVolumes.contains(volume)) {
sStorageVolumes.add(volume);
}
sMountPoints.add(internal_path);
Method method_getSecondaryStoragePath = null;
Method method_getInterHardDiskPath = null;
Method method_getExtUsb0Path = null;
Method method_getExtUsb1Path = null;
Method method_getExtUsb2Path = null;
Method method_getExtUsb3Path = null;
Method method_getExtUsb4Path = null;
Method method_getExtUsb5Path = null;
try {
method_getExtUsb0Path = Environment.class.getMethod(
"getHostStorage_Extern_0_Directory", new Class[] {});
method_getExtUsb1Path = Environment.class.getMethod(
"getHostStorage_Extern_1_Directory", new Class[] {});
method_getExtUsb2Path = Environment.class.getMethod(
"getHostStorage_Extern_2_Directory", new Class[] {});
method_getExtUsb3Path = Environment.class.getMethod(
"getHostStorage_Extern_3_Directory", new Class[] {});
method_getExtUsb4Path = Environment.class.getMethod(
"getHostStorage_Extern_4_Directory", new Class[] {});
method_getExtUsb5Path = Environment.class.getMethod(
"getHostStorage_Extern_5_Directory", new Class[] {});
method_getSecondaryStoragePath = Environment.class.getMethod(
"getSecondVolumeStorageDirectory", new Class[] {});
method_getInterHardDiskPath = Environment.class.getMethod(
"getInterHardDiskStorageDirectory", new Class[] {});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if (method_getSecondaryStoragePath != null) {
String secondaryPath = null;
try {
secondaryPath = ((File) method_getSecondaryStoragePath.invoke(
null, null)).getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (secondaryPath != null) {
IfStorageVolume if_volume = new IfStorageVolume(secondaryPath,
false, true, false);
sMountPointVolumeMap.put(secondaryPath, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(secondaryPath);
}
}
if (method_getInterHardDiskPath != null) {
String interDiskPath = null;
try {
interDiskPath = ((File) method_getInterHardDiskPath.invoke(
null, null)).getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (interDiskPath != null) {
IfStorageVolume if_volume = new IfStorageVolume(interDiskPath,
false, false, false);
sMountPointVolumeMap.put(interDiskPath, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(interDiskPath);
}
}
if (method_getExtUsb0Path != null) {
String usb0path = null;
try {
usb0path = ((File) method_getExtUsb0Path.invoke(null, null))
.getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (usb0path != null) {
IfStorageVolume if_volume = new IfStorageVolume(usb0path,
false, true, false);
sMountPointVolumeMap.put(usb0path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(usb0path);
}
}
if (method_getExtUsb1Path != null) {
String usb1path = null;
try {
usb1path = ((File) method_getExtUsb1Path.invoke(null, null))
.getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (usb1path != null) {
IfStorageVolume if_volume = new IfStorageVolume(usb1path,
false, true, false);
sMountPointVolumeMap.put(usb1path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(usb1path);
}
}
if (method_getExtUsb2Path != null) {
String usb2path = null;
try {
usb2path = ((File) method_getExtUsb2Path.invoke(null, null))
.getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (usb2path != null) {
IfStorageVolume if_volume = new IfStorageVolume(usb2path,
false, true, false);
sMountPointVolumeMap.put(usb2path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(usb2path);
}
}
if (method_getExtUsb3Path != null) {
String usb3path = null;
try {
usb3path = ((File) method_getExtUsb3Path.invoke(null, null))
.getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (usb3path != null) {
IfStorageVolume if_volume = new IfStorageVolume(usb3path,
false, true, false);
sMountPointVolumeMap.put(usb3path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(usb3path);
}
}
if (method_getExtUsb4Path != null) {
String usb4path = null;
try {
usb4path = ((File) method_getExtUsb4Path.invoke(null, null))
.getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (usb4path != null) {
IfStorageVolume if_volume = new IfStorageVolume(usb4path,
false, true, false);
sMountPointVolumeMap.put(usb4path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(usb4path);
}
}
if (method_getExtUsb5Path != null) {
String usb5path = null;
try {
usb5path = ((File) method_getExtUsb5Path.invoke(null, null))
.getPath();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (usb5path != null) {
IfStorageVolume if_volume = new IfStorageVolume(usb5path,
false, true, false);
sMountPointVolumeMap.put(usb5path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(usb5path);
}
}
}
private void initializeIfStorageVolumesInner(
ArrayList<Object> android_storageVolumes) {
boolean androidStorageVolumeAvailable = false;
Class<?> class_StorageVolume = null;
if (android_storageVolumes != null && !android_storageVolumes.isEmpty()) {
try {
class_StorageVolume = Class
.forName("android.os.storage.StorageVolume");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (class_StorageVolume != null
&& android_storageVolumes.get(0).getClass()
.equals(class_StorageVolume)) {
androidStorageVolumeAvailable = true;
}
}
// Create IfStorageVolumes by android StorageVolume
if (androidStorageVolumeAvailable) {
boolean methodAccessiable = false;
Method method_getPath = null;
Method method_isPrimary = null;
Method method_isRemovable = null;
Method method_isEmulated = null;
try {
method_getPath = class_StorageVolume.getMethod("getPath",
new Class[] {});
method_isPrimary = class_StorageVolume.getMethod("isPrimary",
new Class[] {});
method_isRemovable = class_StorageVolume.getMethod(
"isRemovable", new Class[] {});
method_isEmulated = class_StorageVolume.getMethod("isEmulated",
new Class[] {});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if (method_getPath != null && method_isPrimary != null
&& method_isRemovable != null && method_isEmulated != null) {
methodAccessiable = true;
}
if (methodAccessiable) {
String path = null;
Boolean isPrimary = null;
Boolean isRemovable = null;
Boolean isEmulated = null;
for (int i = 0; i < android_storageVolumes.size(); i++) {
Object android_volume = android_storageVolumes.get(i);
try {
path = (String) method_getPath.invoke(android_volume,
new Object[] {});
isPrimary = (Boolean) method_isPrimary.invoke(
android_volume, new Object[] {});
isRemovable = (Boolean) method_isRemovable.invoke(
android_volume, new Object[] {});
isEmulated = (Boolean) method_isEmulated.invoke(
android_volume, new Object[] {});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (path != null) {
IfStorageVolume if_volume = new IfStorageVolume(path,
isPrimary ? isPrimary.booleanValue() : false,
isRemovable ? isRemovable.booleanValue()
: false,
isEmulated ? isEmulated.booleanValue() : false);
sMountPointVolumeMap.put(path, if_volume);
if (!sStorageVolumes.contains(if_volume)) {
sStorageVolumes.add(if_volume);
}
sMountPoints.add(path);
}
}
}
}
// Create IfStorageVolumes by proc
createIfStorageVolumesByProc();
// Fulfill IfStorageVolume fields by Linux /proc/mounts file
fulfillIfStorageVolumesByProc();
}
protected String cacheId(String path, String idTag, String idValue) {
String newValue = idValue;
HashMap<String, String> map = sStorageIdMap.get(idTag);
if (map == null) { // Can't cache, just return
return newValue;
}
map.put(path, idValue);
return newValue;
}
}